package com.link_with_health.controller;

import com.alibaba.fastjson.JSONObject;
import com.link_with_health.common.Page;
import com.link_with_health.common.Result;
import com.link_with_health.common.TokenMap;
import com.link_with_health.exception.NullQueryResultException;
import com.link_with_health.model.AdminLogEntity;
import com.link_with_health.model.AdminUserEntity;
import com.link_with_health.model.BatchModel;
import com.link_with_health.model.InquiryEntity;
import com.link_with_health.model.PatientEntity;
import com.link_with_health.model.SysInfoEntity;
import com.link_with_health.model.UserEntity;
import com.link_with_health.service.AdminLogService;
import com.link_with_health.service.BatchOperationService;
import com.link_with_health.service.DepartmentsService;
import com.link_with_health.service.DoctorService;
import com.link_with_health.service.InquiryService;
import com.link_with_health.service.PatientService;
import com.link_with_health.service.SysInfoService;
import com.link_with_health.utils.JsonUtil;
import com.link_with_health.webSocket.NotificationServer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.*;
import java.util.stream.Collectors;

@Controller
@RequestMapping("/api/inquiry")
public class InquiryController {
    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    private final String AUTH_TOKEN = "Authorization";
    private TokenMap tokenMap = TokenMap.getInstance();

    @Resource(name = "inquiryService")
    InquiryService inquiryService;

    @Resource(name = "doctorService")
    DoctorService doctorService;

    @Resource(name = "patientService")
    PatientService patientService;

    @Resource(name = "sysInfoService")
    SysInfoService sysInfoService;

    @Resource(name = "adminLogService")
    AdminLogService adminLogService;

    @Resource(name = "batchOperationService")
    BatchOperationService batchOperationService;

    /**
     * 获取会诊信息
     * @param json 数据
     * @param request 请求
     * @return 结果
     */
    @RequestMapping("/findInquiryInfo")
    @ResponseBody
    public Result findInquiryInfo(@RequestBody JSONObject json
            , HttpServletRequest request){

        String token = request.getHeader(AUTH_TOKEN);
        String msg = "验签验证失败";
        if(token == null || !tokenMap.containsKey(token)){
            logger.error("[get inquiry failed by token]");
            return Result.fail(msg);
        }

        try {
            String method = json.getString("method");
            String paramsStr = json.getJSONObject("params")
                    .toJSONString();

            HashMap<String, Object> params = JsonUtil.json2obj(paramsStr
                    , HashMap.class);

            return method(method,params);

        } catch (Exception e){
            logger.error("[get inquiry info failed]",e);
            msg = "查找失败";
            if(e instanceof NullQueryResultException){
                return Result.notResult("无查找结果","NULL");
            }

        }

        return Result.fail(msg);
    }

    /**
     * 添加会诊信息
     * @param json 数据
     * @param request 请求
     * @return 结果
     */
    @RequestMapping("/addInquiryInfo")
    @ResponseBody
    public Result addInquiryInfo(@RequestBody JSONObject json
            , HttpServletRequest request){
        String token = request.getHeader(AUTH_TOKEN);
        String msg = "验签验证失败";

        if(token==null|| !tokenMap.containsKey(token)){
            logger.error("[get patient info failed]");
            return Result.fail(msg);
        }
        Integer adminId = Math.toIntExact(tokenMap.get(token)
                instanceof AdminUserEntity
                ? ((AdminUserEntity) tokenMap.get(token)).getAdminID()
                : ((UserEntity) tokenMap.get(token)).getUserId());

        try{
            InquiryEntity entity = JsonUtil
                    .json2obj(json.toJSONString(),InquiryEntity.class);

            inquiryService.addInquiry(entity);
            entity = inquiryService.getInquiryById(entity.getCaseId());

            //备份
            String object = JsonUtil.obj2json(entity);
            AdminLogEntity log = new AdminLogEntity(0L, adminId
                    ,"增加", "inquiry", object);

            adminLogService.addAdminLog(log);

            return Result.success("成功修改",entity);

        }catch(Exception e){
            logger.error("[add inquiry info failed]",e);
            msg = "操作失败 请检查输入的参数";
        }

        return Result.fail(msg);
    }

    /**
     * 修改会诊信息
     * @param json 数据
     * @param request 请求
     * @return 结果
     */
    @RequestMapping("/modifyInquiryInfo")
    @ResponseBody
    public Result modifyInquiryInfo(@RequestBody JSONObject json
            , HttpServletRequest request){
        String token = request.getHeader(AUTH_TOKEN);
        String msg = "验签验证失败";

        if(token==null|| !tokenMap.containsKey(token)){
            logger.error("[get patient info failed]");
            return Result.fail(msg);
        }
        Integer adminId = Math.toIntExact(tokenMap.get(token)
                instanceof AdminUserEntity
                ? ((AdminUserEntity) tokenMap.get(token)).getAdminID()
                : ((UserEntity) tokenMap.get(token)).getUserId());

        try{
            InquiryEntity entity = JsonUtil
                    .json2obj(json.toJSONString(), InquiryEntity.class);

            InquiryEntity oldEntity = inquiryService
                    .getInquiryById(entity.getCaseId());

            inquiryService.changeInquiry(entity);

            entity = inquiryService.getInquiryById(entity.getCaseId());

            //备份
            String object = JsonUtil.obj2json(oldEntity);
            AdminLogEntity log = new AdminLogEntity(0L, adminId
                    , "修改","inquiry", object);

            adminLogService.addAdminLog(log);

            return Result.success("操作成功",entity);

        }catch(Exception e){
            logger.error("[modify failed]",e);
            msg = "操作失败";
        }

        return Result.fail(msg);
    }

    /**
     * 删除会诊信息
     * @param json 数据
     * @param request 请求
     * @return 结果
     */
    @RequestMapping("/deleteInquiryInfo")
    @ResponseBody
    public Result deleteInquiryInfo(@RequestBody JSONObject json
            , HttpServletRequest request){

        String token = request.getHeader(AUTH_TOKEN);
        String msg = "验签验证失败";

        if(token==null|| !tokenMap.containsKey(token)){
            logger.error("[get patient info failed]");
            return Result.fail(msg);
        }

        Integer adminId = Math.toIntExact(tokenMap.get(token)
                instanceof AdminUserEntity
                ? ((AdminUserEntity) tokenMap.get(token)).getAdminID()
                : ((UserEntity) tokenMap.get(token)).getUserId());

        try{
            Long[] ids = json.getObject("ids",Long[].class);
            //备份
            StringBuffer oldEntity = new StringBuffer();

            for(Long idBk : ids){
                InquiryEntity entity = inquiryService.getInquiryById(idBk);

                oldEntity.append("\n").append(JsonUtil.obj2json(entity));
            }

            List<BatchModel> models = new ArrayList<>(ids.length);
            int index = 0;
            //患者id设为10000
            String sql = "t.patient_id = 10000" +
                    " , t.symptom = null, t.diagnosis = null, t.examine = null " +
                    " , t.advice = null, t.medical_history = null" +
                    " , t.presenting_complaint = null " +
                    " , t.history_pc = null";

            for(;index < ids.length; index++){
                BatchModel model = new BatchModel("inquiry",""
                        ,"","case_id",ids[index].toString(),sql);
                models.add(model);
            }

            batchOperationService.batchUpdateLikeDelete(models);

            //记录操作数据
            AdminLogEntity log = new AdminLogEntity(0L, adminId,
                    "删除", "inquiry", oldEntity.toString());
            adminLogService.addAdminLog(log);

            return Result.success("成功操作");

        }catch(Exception e){
            logger.error("delete inquiry failed",e);
            msg = "删除失败";
        }

        return Result.fail(msg);
    }

    /**
     * 保存医生编写的会诊信息
     * @param json 数据
     * @param request 请求
     * @return 结果
     */
    @RequestMapping("/saveInquiry")
    @ResponseBody
    public Result saveInquiry(@RequestBody JSONObject json
            , HttpServletRequest request){

        String token = request.getHeader(AUTH_TOKEN);
        String msg = "验签验证失败";

        if(token==null|| !tokenMap.containsKey(token)){
            logger.error("[get patient info failed]");
            return Result.fail(msg);
        }

        try{
            Long userId = ((UserEntity) tokenMap.get(token)).getUserId();
            Long drId = doctorService.getDoctorsByUserId(userId).getDrId();

            InquiryEntity entity = JsonUtil.json2obj(
                    json.toJSONString(),InquiryEntity.class);
            if(entity.getDrId() == drId){
                inquiryService.changeInquiry(entity);
                entity = inquiryService.getInquiryById(entity.getCaseId());

                return Result.success("保存成功",entity);
            }

        }catch(Exception e){
            logger.error("[save inquiry info failed]",e);
            msg = "保存失败";
        }

        return Result.fail(msg);
    }

    /**
     * 获取指定id的会诊信息
     * @param json 数据 inquiryId
     * @param request 请求
     * @return 结果
     */
    @RequestMapping("/selectInquiryById")
    @ResponseBody
    public Result selectInquiryById(@RequestBody JSONObject json
            , HttpServletRequest request){
        String token = request.getHeader(AUTH_TOKEN);
        String msg = "验签验证失败";
        if(token==null|| !tokenMap.containsKey(token)){
            logger.error("[get inquiry info failed]");
            return Result.fail(msg);
        }

        try{
            Long inquiryId = json.getLong("inquiryId");
            InquiryEntity inquiry = inquiryService
                    .getInquiryById(inquiryId);
            return Result.success("获取成功",inquiry);

        }catch(Exception e){
            logger.error("[get patient info failed]",e);
            msg = "获取会诊信息失败";
        }

        return Result.fail(msg);
    }


    /**
     * 历史会诊信息
     * @param json 数据 userType userId(患者的用户Id) doctorId
     * @param request 请求
     * @return 结果
     */
    @RequestMapping("/getHistoryInquiry")
    @ResponseBody
    public Result getHistoryInquiry(@RequestBody JSONObject json
            , HttpServletRequest request){
        String msg = "验签失败";
        String token = request.getHeader(AUTH_TOKEN);

        if(token == null || !tokenMap.containsKey(token)){
            logger.error("[get inquiry failed by token]");
            return Result.fail(msg);
        }


        try{
            Long userId = ((UserEntity) tokenMap.get(token))
                    .getUserId();

            Boolean isDoctor = ((UserEntity) tokenMap.get(token))
                    .getIsDoctor();

            String userType = json.getString("userType");

            //当userType 为患者时 获取 userId(请求参数) 的所有问诊资料
            if("patient".equals(userType) && userId.equals
                    (json.getLong("userId"))) {

                List<InquiryEntity> list = inquiryService
                        .getInquiryByUserId(userId);

                //过滤
                list = inquiryFilter(list);

                return Result.success(list);

            }
            //当userType 为医生时 获取 doctorId(请求参数) 的所有问诊资料
            else if("doctor".equals(userType) && isDoctor ){
                Long doctorId = json.getLong("doctorId");

                List<InquiryEntity> list = inquiryService
                        .getInquiryByDrId(doctorId);

                //过滤
                list = inquiryFilter(list);

                return Result.success(list);
            }


        }catch(Exception e){
            logger.error("[get inquiry history failed]");
            msg = "获取数据失败";
            if(e instanceof NullQueryResultException){
                logger.info("[not inquiry history]");
                return Result.notResult("无历史问诊记录","NULL");
            }
        }

        return Result.fail(msg);
    }

    /**
     * 创建会诊信息
     * @param json 患者id 医生id
     * @param request
     * @return 返回会诊室通讯路径
     */
    @PostMapping("/createInquiry")
    @ResponseBody
    public Result createInquiry(@RequestBody JSONObject json
            , HttpServletRequest request){

        String msg = "验签失败";
        String token = request.getHeader(AUTH_TOKEN);

        if(token == null || !tokenMap.containsKey(token)){
            logger.error("[get inquiry failed by token]");
            return Result.fail(msg);
        }

        try {
            Long userId = ((UserEntity) tokenMap.get(token))
                    .getUserId();
            Long doctorId = json.getLong("doctorId");
            if(doctorId != null && doctorId.equals(doctorService
                    .getDoctorsByUserId(userId).getDrId())){
                InquiryEntity entity = new InquiryEntity();

                entity.setDrId(doctorId);
                entity.setPatientId(json.getLong("patient"));

                inquiryService.addInquiry(entity);

                //获取患者的用户id
                Long patientUserId = patientService
                        .getPatientByPatientId(json.getLong("patient"))
                        .getUserBind();

                SysInfoEntity info = new SysInfoEntity();
                info.setSender(userId);
                info.setReceiver(patientUserId);
                info.setInfoType(4);
                info.setContent("您好，您预约的会诊已开始，请点击以下连接进入诊室");

                //插入信息
                sysInfoService.addSysInfo(info);
                info = sysInfoService.getSysInfoById(info.getId());

                String str = JsonUtil.obj2json(info);
                //广播
                NotificationServer.sendMessageInController(str,patientUserId.toString());

                return Result.success("成功创建",entity);
            }


        }catch(Exception e){
            logger.error("[create inquiry failed]");
            msg = "创建失败";
        }

        return Result.fail(msg);
    }

    /**
     * 通过条件查询数据
     * @param method 方法
     * @param params 参数
     * @return 结果
     * @throws Exception 异常
     */
    private Result method(String method, Map<String,Object> params)
            throws Exception{
        List<InquiryEntity> list = new ArrayList<InquiryEntity>();

        switch(method){
            case "all": case "all-page":{
                list = inquiryService.getAllInquiry();
                list = inquiryFilter(list);
            }
            break;

            case "id-page":{
                String id = String.valueOf(params.get("id"));
                try{
                    list = inquiryService.getInquiryByDrId(Long.valueOf(id));
                }catch(Exception e){
                    logger.warn("[not result by search doctorId]");
                }

                try{
                    if(list == null)
                        list = inquiryService.getInquiryByPatientId(Long.valueOf(id));
                    else
                        list.addAll(inquiryService.getInquiryByPatientId(Long.valueOf(id)));
                }catch(Exception e){
                    logger.warn("[not result by search patientId]");
                }

                try{
                    if(list == null)
                        list = inquiryService.getInquiryByUserId(Long.valueOf(id));
                    else
                        list.addAll(inquiryService.getInquiryByUserId(Long.valueOf(id)));
                }catch(Exception e){
                    logger.warn("[not result by search Id]");
                }

                if(list != null && !list.isEmpty())
                    list = inquiryFilter(list)
                            .stream()
                            .distinct()
                            .collect(Collectors.toList());
            }
                break;

            case "name-page":{
                String name = (String) params.get("name");

                try{
                    if("".equals(name) || name == null)
                        throw new NullPointerException("[name is invalid]");

                    list = inquiryService.getAllInquiry();
                    list = inquiryFilter(list)
                            .stream()
                            .distinct()
                            .collect(Collectors.toList());

                    list = list.stream()
                            .filter(item->(
                                    (item.getDoctorName() != null
                                            && item.getDoctorName().contains(name))
                                    || (item.getPatientName() != null
                                            && item.getPatientName().contains(name))))
                            .collect(Collectors.toList());

                }catch(Exception e){
                    logger.warn("[not result by search name]");
                }
            }
                break;

            default:
                logger.error("unknown method=>" + method);
                return Result.fail("未知查找方法");
        }
        if(list == null || list.isEmpty())
            throw new NullQueryResultException("[not result fo inquiry]");

        //封装 带页数数据
        if(method.contains("page")){


            Integer current = Integer.valueOf(String.valueOf(params.get("current"))) ;
            Integer size = Integer.valueOf(String.valueOf(params.get("size")));
            Page<InquiryEntity> page = new Page<>(list,size,current);
            return Result.success(page.getPageDate());
        }

        return Result.success(list);
    }

    /**
     * 过滤患者id为10000
     * @param list 数据
     * @return  过滤后的数据
     */
    private List<InquiryEntity> inquiryFilter(List<InquiryEntity> list) {
        return list.stream().filter(item -> (10000 != item.getPatientId()))
                .collect(Collectors.toList());
    }

}
